using System;
using System.Collections;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Context;
using PHSRAG.Insight21.Policy;
using PHSRAG.Utility;
using Utils = PHSRAG.Insight21.InsightUtilities;

namespace PHSRAG.Insight21.Humans
{
    /// <summary>
    /// Displays a list of Drug and/or Device addition requests raised by the submitter
    /// </summary>
    public partial class ListRequestPage : BasePage
    {
        #region Constants

        private const string CurrentListKey = "currentListKey_EA2B1A3C-57ED-492e-BC55-5F9B3B397833";
        private const string CurrentPageIndexKey = "CurrentPageIndexKey_EA2B1A3C-57ED-492e-BC55-5F9B3B397833";

        #endregion

        #region Instance Variables (Private)

        private ICachePolicy cachePolicy;
        private ICachePolicy pageCachePolicy;

        #endregion

        #region Private properties

        /// <summary>
        /// Gets the List of addition requests for the logged-in user having admin rights.
        /// </summary>
        private ListAdditionRequests ListAdditionRequests
        {
            get
            {
                ListAdditionRequests listAdditionRequests = cachePolicy.GetCachedObject(ListAdditionRequests.CacheKey) as ListAdditionRequests;
                if (listAdditionRequests == null)
                {
                    listAdditionRequests = new ListAdditionRequests(cachePolicy);
                    UserContext userContext = cachePolicy.GetCachedObject(UserContext.CacheKey) as UserContext;
                    listAdditionRequests.Load(DataAccess.ConnectionString, userContext.DomainUserId);
                    listAdditionRequests.Cache();
                }
                return listAdditionRequests;
            }
        }

        /// <summary>
        /// Get/Set the current page within the datagrid for display. This information persists across page loads.
        /// </summary>
        private int CurrentPageIndex
        {
            get
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.ListAdditionPageKey) as Hashtable;
                return (h == null || h[CurrentPageIndexKey] == null) ? 0 : (int) h[CurrentPageIndexKey];
            }
            set
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.ListAdditionPageKey) as Hashtable ?? new Hashtable();
                h[CurrentPageIndexKey] = value;
                listRequestGrid.CurrentPageIndex = value;
                pageCachePolicy.Cache(Keys.ListAdditionPageKey, h);
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Loads the datagrid with the addition requests
        /// This method uses the DataKeyField to identify the Id of the respective row ,instead of having hidden Id column.
        /// </summary>
        private void LoadDataGrid()
        {
            try
            {
                ListAdditionRequests listAdditionRequests = ListAdditionRequests;
                listRequestGrid.VirtualItemCount = bottomPager.RecordCount =
                    topPager.RecordCount = listAdditionRequests.Count;

                int currentPageIndex = CurrentPageIndex;
                bottomPager.PageCount = topPager.PageCount = (topPager.RecordCount/listRequestGrid.PageSize) +
                    (((topPager.RecordCount%listRequestGrid.PageSize) == 0) ? 0 : 1);
                bottomPager.CurrentPage = topPager.CurrentPage = currentPageIndex + 1;

                ArrayList list = listAdditionRequests.GetAdditionRequestList(
                    currentPageIndex*listRequestGrid.PageSize, listRequestGrid.PageSize);
                listRequestGrid.DataSource = list;
                listRequestGrid.DataKeyField = "Id";
                listRequestGrid.DataBind();

                if (list.Count == 0)
                {
                    gridContainer.Visible = false;
                    annunciator.Message = "No addition requests to display.";
                }
                else
                {
                    gridContainer.Visible = true;
                    annunciator.Message = string.Empty;
                    recordCount.Text = topPager.RecordCount.ToString();
                }
                cachePolicy.Cache(CurrentListKey, list);
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to load the list of addition requests";
            }
        }

        /// <summary>
        /// Sets the pager control with corresponding values(Pagination management)
        /// </summary>
        private void ManagePagination()
        {
            int currentPageIndex = CurrentPageIndex;
            listRequestGrid.CurrentPageIndex = currentPageIndex;

            int startIndex = currentPageIndex*listRequestGrid.PageSize;
            bottomPager.FirstRecord = topPager.FirstRecord = startIndex + 1;

            bottomPager.LastRecord = topPager.LastRecord =
                Math.Min(startIndex + listRequestGrid.PageSize, ListAdditionRequests.Count);

            bottomPager.EnableFirstPage = topPager.EnableFirstPage =
                bottomPager.EnablePreviousPage = topPager.EnablePreviousPage =
                    (listRequestGrid.CurrentPageIndex != 0);

            bottomPager.EnableLastPage = topPager.EnableLastPage =
                bottomPager.EnableNextPage = topPager.EnableNextPage =
                    (listRequestGrid.CurrentPageIndex != (topPager.PageCount - 1));
        }

        #endregion

        #region Web Form Designer generated code

        /// <summary>Initializes components used on the page.</summary>
        /// <param name="e"></param>
        protected override void OnInit(EventArgs e)
        {
            //InitializeComponent();
            base.OnInit(e);
            cachePolicy = (Policy.ICachePolicy) Session[Policy.Names.CachePolicyKey];
            pageCachePolicy = (Policy.ICachePolicy) Session[Policy.Names.PageCachePolicyKey];

            //this.downloadBar.FailedAction += new CommandEventHandler(OnDownloadFailed);
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Sets the bread crumb trail for the page 
        /// Loads the datagrid with addition requests,if !IsPostBack
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            adminHumansSubNavigation.SelectedLink = "Data Management";
            downloadBar.SQLReportName = SSRSRequest.ReportNames.Humans.HumansManagement;
            breadCrumb.Add(
                "Data Management",
                Settings.GetKeyValue("SubNavigation.Admin.Humans.ListRequestURL", ""),
                Settings.GetKeyValue("BreadCrumb.SummaryPageLevel", 1));

            if (!IsPostBack && postbackGuard.IsValid)
            {
                listRequestGrid.PageSize = Settings.GetKeyValue("HumansDataGrid.ItemsPerPage", 20);
                ListAdditionRequests.Load(DataAccess.ConnectionString);
                LoadPage();
            }
        }

        /// <summary>Manages pagination & Navigational Links,Loads datagrid </summary>
        private void LoadPage()
        {
            LoadDataGrid();
            ManagePagination();
        }

        /// <summary>
        /// During data binding of the grid, a tooltip is set for the name columns. 
        /// Accept and reject checkbox(Template columns) are set with the onclick attribute.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnItemDataBound(object sender, DataGridItemEventArgs e)
        {
            try
            {
                if ((e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem))
                {
                    e.Item.Cells[(int) ColumnIndex.Title].ToolTip = ((ListAdditionRequest) e.Item.DataItem).Title;
                    CheckBox accept = (CheckBox) e.Item.FindControl("accept");
                    CheckBox reject = (CheckBox) e.Item.FindControl("reject");
                    accept.Attributes.Add("onClick", "ToggleSelection('" + accept.ClientID + "', '" + reject.ClientID + "')");
                    reject.Attributes.Add("onClick", "ToggleSelection('" + reject.ClientID + "', '" + accept.ClientID + "')");
                    e.Item.Cells[(int) ColumnIndex.Name].ToolTip = e.Item.Cells[(int) ColumnIndex.Name].Text;
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to load the list of addition requests";
            }
        }

        /// <summary>
        /// Occurs when the FirstPage hyperlink is clicked on the pager.
        /// The page's DataGrid is reloaded with the data belonging to the first page.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnFirstPage(object sender, CommandEventArgs e)
        {
            CurrentPageIndex = 0;
            LoadPage();
        }

        /// <summary>
        /// Occurs when the last page hyperlink is clicked on the pager.
        /// The page's DataGrid is reloaded with the data belonging to the last page.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnLastPage(object sender, CommandEventArgs e)
        {
            CurrentPageIndex = topPager.PageCount - 1;
            LoadPage();
        }

        /// <summary>
        /// Occurs when the NextPage hyperlink is clicked on the pager.
        /// The page's DataGrid is reloaded with the data belonging to the next page.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnNextPage(object sender, CommandEventArgs e)
        {
            ++CurrentPageIndex;
            LoadPage();
        }

        /// <summary>
        /// Occurs when the PreviousPage hyperlink is clicked on the pager.
        /// The page's DataGrid is reloaded with the data belonging to the previous page.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnPreviousPage(object sender, CommandEventArgs e)
        {
            --CurrentPageIndex;
            LoadPage();
        }

        /// <summary>Handles sorting events on the datagrid columns.</summary>
        /// <param name="source">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnSort(object source, DataGridSortCommandEventArgs e)
        {
            if (e.SortExpression != string.Empty)
            {
                CurrentPageIndex = 0;
                ListAdditionRequests.Sort(e.SortExpression);
                LoadPage();
            }
        }

        /// <summary>
        /// Sets the command event for the dataitem in the datagrid.Caches the protocolId and the ProtocolProcessId in the outgoing hashkey 
        /// </summary>
        /// <param name="source">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnItemCommand(object source, DataGridCommandEventArgs e)
        {
            try
            {
                if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
                {
                    ArrayList requestList = cachePolicy.GetCachedObject(CurrentListKey) as ArrayList;
                    if (requestList != null)
                    {
                        foreach (ListAdditionRequest additionRequest in requestList)
                        {
                            if (additionRequest.Id == Convert.ToInt32(listRequestGrid.DataKeys[e.Item.ItemIndex]))
                            {
                                Hashtable outgoingData = new Hashtable();
                                outgoingData.Add(Keys.ProtocolProcessIdKey, additionRequest.ProtocolProcessId);
                                outgoingData.Add(Keys.ProtocolIdKey, additionRequest.ProtocolId);
                                pageCachePolicy.Cache(Keys.IncomingDataKey, outgoingData);
                                Page.Response.Redirect(
                                    Settings.GetKeyValue("SubModuleNavigation.Humans.ProtocolProcessOverviewURL", ""), true);
                            }
                        }
                    }
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to load the list of addition requests";
            }
        }

        /// <summary>
        /// Handler for event raised while each data grid item is created.
        /// If the item being created is the data grid header, do the following:
        /// Add the appropriate sort symbol to denote ascending/descending sequence for the current sort column.
        /// This requires us to locate the cell corresponding to the column within the collection of TableCell
        /// maintained by the DataGridItem which is under creation. That collection is indexed numerically, the value being
        /// the position of the column within the columns collection maintained by the data grid.
        /// One simple way to do this is to create static mapping between the name of the column and its index. However, this
        /// suffers from the shortcoming that if the sequence of columns is changed on the page, the static binding must
        /// be changed too. If they get out of sync, we would be sorting on inappropriate columns!
        /// To avoid this, and to render the code independent of how the page gets managed, we will build a Hashtable of
        /// column indices, keyed by the sort expression of each column. That way, we could do a quick lookup to get the
        /// index of a column and set the sort symbol on that column.
        /// If the item being created is a data row item, enable the view state only for the checkbox field(Template columns)and name column
        /// </summary>
        /// <param name="sender">Control which raised the event</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnItemCreated(object sender, DataGridItemEventArgs e)
        {
            try
            {
                if (e.Item.ItemType == ListItemType.Header)
                {
                    ListAdditionRequests requests = ListAdditionRequests;
                    Label sortSymbol = new Label();
                    sortSymbol.Text = requests.SortAscending ? InsightUtilities.Constants.SortAscendingText : InsightUtilities.Constants.SortDescendingText;
                    sortSymbol.Font.Name = InsightUtilities.Constants.SortSymbolFontName;

                    Hashtable columnMap = new Hashtable();
                    foreach (DataGridColumn column in listRequestGrid.Columns)
                    {
                        columnMap[column.SortExpression] = listRequestGrid.Columns.IndexOf(column);
                    }

                    string sortColumn = requests.SortColumn;
                    if (columnMap.ContainsKey(sortColumn))
                    {
                        (e.Item.Cells[(int) columnMap[sortColumn]]).Controls.Add(sortSymbol);
                    }
                }
                else if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
                {
                    for (int i = 0, cellCount = e.Item.Cells.Count; i < cellCount; ++i)
                    {
                        if ((i != (int) ColumnIndex.Accept) && (i != (int) ColumnIndex.Reject) && (i != (int) ColumnIndex.Name))
                        {
                            e.Item.Cells[i].EnableViewState = false;
                        }
                    }
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to load the list of addition requests";
            }
        }

        /// <summary>Iterates through the list of addition requests in the grid and performs the respective accept/reject depending on the checkbox checked 
        /// If the accept checkBox is checked,then the corresponding request entry from the Insight database is removed
        /// Else(Reject checkBox)is checked,then the request entry from both the Insight and the legacy database is removed</summary>
        /// <param name="sender">The object that initiated the action</param>
        /// <param name="e">arguments for the event</param>
        protected void OnUpdate(object sender, EventArgs e)
        {
            try
            {
                for (int i = 0, gridRowCount = listRequestGrid.Items.Count; i < gridRowCount; ++i)
                {
                    DataGridItem dgItem = listRequestGrid.Items[i];
                    CheckBox accept = ((CheckBox) dgItem.Cells[(int) ColumnIndex.Accept].Controls[1]);
                    CheckBox reject = ((CheckBox) dgItem.Cells[(int) ColumnIndex.Reject].Controls[1]);
                    ListAdditionRequest listAdditionRequest = new ListAdditionRequest(cachePolicy);
                    listAdditionRequest.Id = Convert.ToInt32(listRequestGrid.DataKeys[i]);
                    if (reject.Checked)
                    {
                        ArrayList requestList = cachePolicy.GetCachedObject(CurrentListKey) as ArrayList;
                        if (requestList != null)
                        {
                            foreach (ListAdditionRequest additionRequest in requestList)
                            {
                                if (additionRequest.Id == Convert.ToInt32(listRequestGrid.DataKeys[i]))
                                {
                                    listAdditionRequest.RexId = additionRequest.RexId;
                                    listAdditionRequest.Reject(DataAccess.GetConnectionString(InsightUtilities.Constants.RexDatabaseKey), DataAccess.ConnectionString);
                                    break;
                                }
                            }
                        }
                    }
                    else if (accept.Checked)
                    {
                        listAdditionRequest.Accept(DataAccess.ConnectionString);
                    }
                }
                ListAdditionRequests.Load(DataAccess.ConnectionString);
                LoadPage();
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to update list of addition requests";
            }
        }

        /// <summary>
        /// Resets the subnavigation selected link(s) before the 
        /// header performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnHeaderNavigate(object sender, CommandEventArgs e)
        {
            adminSubNavigation.Reset();
            adminHumansSubNavigation.Reset();
        }

        #endregion

        #region Download Bar Handlers/Helpers

        /// <summary>
        /// Invoked by the download bar when it catches an exception.
        /// </summary>
        /// <param name="sender">Control which raised the event</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnDownloadFailed(object sender, CommandEventArgs e)
        {
            annunciator.Title = "Following error(s) occurred while downloading";
            annunciator.Message = ExceptionReport.GetExceptionInfo((Exception) e.CommandArgument, false);
        }

        #endregion

        #region ColumnIndex Enum

        /// <summary>
        /// Provides indices used in the datagrid for specific columns
        /// </summary>
        private enum ColumnIndex
        {
            /// <summary>Category column index</summary>
            Category,
            /// <summary>ProtocolNumber column index</summary>
            ProtocolNumber,
            /// <summary>Protocol Title column index</summary>
            Title,
            /// <summary>DateCreated column index</summary>
            DateCretaed,
            /// <summary>Name column index</summary>
            Name,
            /// <summary>Submitter column index</summary>
            Submitter,
            /// <summary>Accept(CheckBox) column index</summary>
            Accept,
            /// <summary>Reject(CheckBox) column index</summary>
            Reject
        }

        #endregion
    }
}